#include <everest/dbc/odbc/odbc_common.h>
#include <vector>
#include <string.h>
#include <stdio.h>

using namespace NS_EVEREST::dbc::odbc;
using namespace NS_EVEREST::dbc;
using namespace NS_EVEREST;
using namespace std;

OdbcException::OdbcException() throw()
: m_Code(0)
{
	m_State[0]  = '\0';
	m_Source[0] = '\0';
	m_Message[0] = '\0';
}
OdbcException::OdbcException(int code, const char *message, const char *source) throw()
	: m_Code(code)
{
	m_State[0] = '\0';
	m_Source[0] = '\0';
	m_Source[63] = '\0';
	m_Message[0] = '\0';
	m_Message[SQL_MAX_MESSAGE_LENGTH - 1] = '\0';
	strncpy((char *)m_Message, message?message:"<EMPTY>", SQL_MAX_MESSAGE_LENGTH - 1);
	strncpy((char *)m_Source, source?source:"<EMPTY>", 63);
}

OdbcException::OdbcException(SQLSMALLINT handleType, SQLHANDLE handle, const char *pszSource) throw()
: m_Code(0)
{
	m_State[0]  = '\0';
	m_Source[0] = '\0';
	m_Message[0] = '\0';

	this->set(handleType, handle, pszSource);
}

OdbcException::OdbcException(const OdbcException &e) throw()
: m_Code(0)
{
	this->m_Code = e.m_Code;
	strcpy((char *)m_State,  (const char *)e.m_State);
	strcpy((char *)m_Source, (const char *)e.m_Source);
	strcpy((char *)m_Message, (const char *)e.m_Message);

}

OdbcException::~OdbcException() throw()
{
	// EMPTY
}

OdbcException& OdbcException::operator =(const OdbcException& e) throw()
{
	this->m_Code = e.m_Code;
	strcpy((char *)m_State,  (const char *)e.m_State);
	strcpy((char *)m_Source, (const char *)e.m_Source);
	strcpy((char *)m_Message, (const char *)e.m_Message);

	return *this;
}

void OdbcException::set(SQLSMALLINT handleType, SQLHANDLE handle, const char *pszSource) throw()
{
	SQLSMALLINT mlen = 0;
	SQLGetDiagRec(handleType, handle, 1, m_State, &m_Code, m_Message, SQL_MAX_MESSAGE_LENGTH, &mlen);

	if (pszSource) {
		strncpy((char *)m_Source, (const char *)pszSource, 64);
		m_Source[63] = '\0';
	}
	m_Code = SQL_ERROR;
	return ;
}

int OdbcException::code() const
{
	return (int)this->m_Code;
}

String OdbcException::state() const
{
	return String((const char *)this->m_State);
}

String OdbcException::message() const
{
	return String((const char *)m_Message);
}

String OdbcException::source() const
{
	return String((const char *)this->m_Source);
}

OdbcException OdbcException::InvalidHandle(SQLSMALLINT handleType, SQLHANDLE handle, const char *pszSource)
{
	OdbcException e;

	const char *dbc = "DBC";
	const char *env = "ENV";
	const char *stm = "STMT";
	const char *des = "DESC";
	const char *type = "UNKNOWN";
	switch (handleType)
	{
	case SQL_HANDLE_ENV: type = env; break;
	case SQL_HANDLE_DBC: type = dbc; break;
	case SQL_HANDLE_STMT: type = stm; break;
	case SQL_HANDLE_DESC: type = des; break;
	}

	e.m_Code = SQL_INVALID_HANDLE;
	snprintf((char *)e.m_Message, SQL_MAX_MESSAGE_LENGTH,
		"Invalid %s handle %p, maybe closed already.", type, handle);
	if( pszSource ) {
		strncpy((char *)e.m_Source, pszSource, 63);
		e.m_Source[63] = '\0';
	}
	return e;
}

OdbcException OdbcException::InvalidColumnIndex(int colIndex, int min, int max, const char *pszSource)
{
	OdbcException e;
	e.m_Code = SQL_ERROR;
	snprintf((char *)e.m_Message, SQL_MAX_MESSAGE_LENGTH,
		"Invalid column index (%d), valid range is %d - %d.", colIndex, min, max);
	if( pszSource ) {
		strncpy((char *)e.m_Source, pszSource, 63);
		e.m_Source[63] = '\0';
	}
	return e;
}

OdbcException OdbcException::InvalidTypeCast(int colIndex, SQLSMALLINT ctype, const char *nativeType, const char *pszSource)
{
	OdbcException e;
	e.m_Code = SQL_ERROR;
	snprintf((char *)e.m_Message, SQL_MAX_MESSAGE_LENGTH,
		"Invalid type casting, columnIndex(%d), SQLTYPE(%d), native type(%s)", colIndex, ctype, nativeType);
	if( pszSource ) {
		strncpy((char *)e.m_Source, pszSource, 63);
		e.m_Source[63] = '\0';
	}
	return e;
}
